package com.easyban.aspect;


import com.easyban.Dto.SessionWebUserDto;
import com.easyban.annotation.GlobalInterceptor;
import com.easyban.annotation.VerifyParam;
import com.easyban.config.WebConfig;
import com.easyban.constants.Constants;
import com.easyban.entity.enums.DateTimePatternEnum;
import com.easyban.entity.enums.ResponseCodeEnum;
import com.easyban.entity.vo.ResponseVO;
import com.easyban.exception.BusinessException;
import com.easyban.utils.DateUtil;
import com.easyban.utils.StringTools;
import com.easyban.utils.VerifyUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;

@Aspect
@Component
public class OperationAspect {
    private static Logger log = LoggerFactory.getLogger(OperationAspect.class);
@Resource
private WebConfig webConfig;


    private static final String TYPE_STRING = "java.lang.String";
    private static final String TYPE_INTEGER = "java.lang.Integer";
    private static final String TYPE_LONG = "java.lang.Long";
    @Pointcut("@annotation(com.easyban.annotation.GlobalInterceptor)")
    private void requestInterceptor(){}
    @Around("requestInterceptor()")
    public Object interceptorDo(ProceedingJoinPoint point) {
     try {
         Object target = point.getTarget();
         Object[] args = point.getArgs();

         String methodName = point.getSignature().getName();//获取目标的方法名
         Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
         Method method = target.getClass().getMethod(methodName, parameterTypes);
         GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);
         if (interceptor==null){
             return null;
         }

       //  校验登录

         if (interceptor.checkLogin()) {
             checkLogin();
         }

         /**
          * 校验参数
          */
         if (interceptor.checkParams()) {
             validateParams(method, args);
         }
       /*
       * 校验是否是管理员*/
         if (interceptor.checkAdmin()){
             checkAdmin();
         }
         Object pointResult = point.proceed();


         return pointResult;
     } catch (BusinessException e){
         log.error("全局拦截器异常3", e);
         throw e;
     } catch (Exception e) {
         log.error("全局拦截器异常1", e);
         throw new BusinessException(ResponseCodeEnum.CODE_500);
     } catch (Throwable e) {
         log.error("全局拦截器异常2", e);
         throw new BusinessException(ResponseCodeEnum.CODE_500);
     }

    }

    private void checkAdmin() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        SessionWebUserDto sessionAttribute = (SessionWebUserDto)session.getAttribute(Constants.SESSION_KEY);
        if (!sessionAttribute.getAdmin()){
            throw new BusinessException(ResponseCodeEnum.CODE_902);
        }
    }


    private void checkLogin() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        SessionWebUserDto obj = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        if (obj==null){
           throw  new BusinessException(ResponseCodeEnum.CODE_901);
        }
    }

    private void validateParams(Method method, Object[] args) {
        Parameter[] parameters = method.getParameters();
        for (int i=0;i<parameters.length;i++){
           Parameter parameter=parameters[i];
           Object value= args[i];
            VerifyParam verifyParam = parameter.getAnnotation(VerifyParam.class);
            if (verifyParam==null){
                continue;
            }

            //基本数据类型
            if (TYPE_STRING.equals(parameter.getParameterizedType().getTypeName()) || TYPE_LONG.equals(parameter.getParameterizedType().getTypeName()) || TYPE_INTEGER.equals(parameter.getParameterizedType().getTypeName())) {
                checkValue(value, verifyParam);
                //如果传递的是对象
            } else {
                checkObjValue(parameter, value);
            }
        }
    }

    private void checkObjValue(Parameter parameter, Object value) {
        try {
            String typeName = parameter.getParameterizedType().getTypeName();
            Class classz = Class.forName(typeName);
            Field[] fields = classz.getDeclaredFields();
            for (Field field : fields) {
                VerifyParam fieldVerifyParam = field.getAnnotation(VerifyParam.class);
                if (fieldVerifyParam == null) {
                    continue;
                }
                field.setAccessible(true);
                Object resultValue = field.get(value);
                checkValue(resultValue, fieldVerifyParam);
            }
        } catch (BusinessException e) {
            log.error("校验参数失败", e);
            throw e;
        } catch (Exception e) {
            log.error("校验参数失败", e);
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
    }

    private void checkValue(Object value, VerifyParam verifyParam) {
    Boolean isEmpty=value == null || StringTools.isEmpty(value.toString());
    Integer length = value == null ? 0 : value.toString().length();
        //校验空ui
        if (isEmpty && verifyParam.required()){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        if (!isEmpty && (verifyParam.max() != -1 && verifyParam.max() < length || verifyParam.min() != -1 && verifyParam.min() > length)) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        /**
         * 校验正则
         */
        if (!isEmpty && !StringTools.isEmpty(verifyParam.regex().getRegex()) && !VerifyUtils.verify(verifyParam.regex(), String.valueOf(value))) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
    }



}

